import numpy as np
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn import preprocessing
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report

from tools.plot_model import plot_singleModel

import warnings
warnings.filterwarnings("ignore")


def knn(filePath):
    accuracy_list, precision_list, recall_list, f1_list = [], [], [], []
    data = pd.read_csv(filePath)
    # print(data)
    column_names = ['loc', 'v(g)', 'ev(g)', 'iv(g)', 'n', 'v', 'l', 'd', 'i', 'e', 'b', 't', 'lOCode', 'lOComment', 'lOBlank', 'lOCodeAndComment', 'uniq_Op', 'uniq_Opnd', 'total_Op', 'total_Opnd', 'branchCount']
    # print(column_names)
    df = pd.DataFrame(data=data, columns=column_names)
    # print(df)
    y = pd.DataFrame(data=data, columns=['defects'])
    # print(y)
    from imblearn.over_sampling import SMOTE
    from imblearn.under_sampling import TomekLinks
    # 创建 SMOTE 对象
    smote = SMOTE(sampling_strategy=1.0, random_state=42)  # 1.0 表示将类别1的数量提升到类别0的数量
    # 使用 SMOTE 进行过采样
    X_resampled, y_resampled = smote.fit_resample(df, y)

    # 使用 TomekLinks 进行欠采样
    tl = TomekLinks(sampling_strategy='auto')
    X_resampled, y_resampled = tl.fit_resample(X_resampled, y_resampled)

    # print(X_resampled)
    # print(y_resampled)

    # 创建PCA实例并拟合数据
    pca = PCA(n_components=3)  # 选择要保留的主成分数量
    X_pca = pca.fit_transform(X_resampled)  # X是你的特征矩阵

    for i in range(1, 11):
        X_train, X_test, y_train, y_test = train_test_split(X_pca, y_resampled, test_size=0.3)
        # print(X_train)
        # print(y_train)

        X_train = np.array(X_train)
        X_test = np.array(X_test)
        y_train = np.array(y_train)
        y_test = np.array(y_test)

        knn = KNeighborsClassifier(n_neighbors=6, weights='distance', p=1)  # 使用optuna的优化结果创建模型
        knn.fit(X_train, y_train)  # X_train是训练数据的特征，y_train是对应的标签

        y_pred = knn.predict(X_test)  # X_test是测试数据的特征

        # 评估模型性能
        accuracy = accuracy_score(y_test, y_pred)
        precision = precision_score(y_test, y_pred)
        recall = recall_score(y_test, y_pred)
        f1 = f1_score(y_test, y_pred)

        # 打印模型性能指标
        print("第", i, "次:")
        print("Accuracy:", accuracy)
        print("Precision:", precision)
        print("Recall:", recall)
        print("F1 Score:", f1)

        accuracy_list.append(accuracy)
        precision_list.append(precision)
        recall_list.append(recall)
        f1_list.append(f1)

        # report = classification_report(y_test, y_pred)
        # print(report)

    print('平均准确率:', np.mean(accuracy_list))  # 准确率
    print('平均精确率:', np.mean(precision_list))  # 精确率
    print('平均召回率:', np.mean(recall_list))  # 召回率
    print('平均f1值:', np.mean(f1_list))

    return accuracy_list, precision_list, recall_list, f1_list

if __name__ == "__main__":
    filePath = "../data/KC2.csv"
    accuracy_list, precision_list, recall_list, f1_list = knn(filePath)
    # plot_singleModel("KNN", accuracy_list, precision_list, recall_list, f1_list)